import { schemaComposer } from '../..';

const typeDefs = `
# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.

schema {
  query: Query
  mutation: Mutation
  subscription: Subscription
}

directive @customDirective(level: Int!) on FIELD

directive @defer(
  label: String!
  if: Boolean = true
) on FRAGMENT_SPREAD | INLINE_FRAGMENT

directive @stream(
  label: String!
  initial_count: Int!
  if: Boolean = true
) on FIELD

type Query {
  checkinSearchQuery(query: CheckinSearchInput): CheckinSearchResult
  defaultSettings: Settings,
  route(waypoints: [WayPoint!]!): Route
  items(filter: ItemFilterInput): ItemFilterResult
  maybeNode: MaybeNode
  neverNode: NeverNode
  named: Named
  me: User
  node(id: ID): Node
  node_id_required(id: ID!): Node
  nodes(ids: [ID!]): [Node]
  settings(environment: Environment): Settings
  story: Story
  task(number: Int): Task
  username(name: String!): Actor
  usernames(names: [String!]!): [Actor]
  viewer: Viewer
  _mutation: Mutation
}

union MaybeNode = Story | FakeNode | NonNode

type FakeNode {
  id: ID!
}

type NonNode {
  id: String
  name: String
}

union NeverNode = FakeNode | NonNode

type Task {
  title: String
}

input WayPoint {
  lat: String
  lon: String
}

type Route {
  steps: [RouteStep]
}

type RouteStep {
  lat: String
  lon: String
  note: String
}

type Mutation {
  actorSubscribe(input: ActorSubscribeInput): ActorSubscribeResponsePayload
  actorNameChange(input: ActorNameChangeInput): ActorNameChangePayload
  applicationRequestDeleteAll(input: ApplicationRequestDeleteAllInput): ApplicationRequestDeleteAllResponsePayload
  commentCreate(input: CommentCreateInput): CommentCreateResponsePayload
  commentDelete(input: CommentDeleteInput): CommentDeleteResponsePayload
  feedbackLike(input: FeedbackLikeInput): FeedbackLikeResponsePayload
  feedbackLikeSubscribe(input: FeedbackLikeInput): FeedbackLikeResponsePayload
  nodeSavedState(input: NodeSaveStateInput): NodeSavedStateResponsePayload
  unfriend(input: UnfriendInput): UnfriendResponsePayload
  viewerNotificationsUpdateAllSeenState(input: UpdateAllSeenStateInput): ViewerNotificationsUpdateAllSeenStateResponsePayload
}

type Subscription {
  feedbackLikeSubscribe(input: FeedbackLikeInput): FeedbackLikeResponsePayload
  commentCreateSubscribe(input: CommentCreateSubscriptionInput): CommentCreateResponsePayload
}

input ActorSubscribeInput {
  clientMutationId: String
  subscribeeId: ID
}

input ActorNameChangeInput {
  clientMutationId: String
  newName: String
}

input ApplicationRequestDeleteAllInput {
  clientMutationId: String
  deletedRequestIds: [ID]
}

input CommentCreateInput {
  clientMutationId: String
  feedbackId: ID
  feedback: CommentfeedbackFeedback
}

input CommentfeedbackFeedback {
  comment: FeedbackcommentComment
}

input FeedbackcommentComment {
  feedback: CommentfeedbackFeedback
}

input CommentCreateSubscriptionInput {
  clientSubscriptionId: String
  feedbackId: ID
  text: String
}

input CommentDeleteInput {
  clientMutationId: String
  commentId: ID
}

input FeedbackLikeInput {
  clientMutationId: String
  feedbackId: ID
}

input NodeSaveStateInput {
  clientMutationId: String
  nodeId: ID
}

input UpdateAllSeenStateInput {
  clientMutationId: String
  storyIds: [ID]
}

type ActorSubscribeResponsePayload {
  clientMutationId: String
  subscribee: Actor
}

type ActorNameChangePayload {
  clientMutationId: String
  actor: Actor
}

type ApplicationRequestDeleteAllResponsePayload {
  clientMutationId: String
  deletedRequestIds: [ID]
}

type CheckinSearchResult {
  query: String
}

input CheckinSearchInput {
  query: String
  inputs: [CheckinSearchInput]
}

type PlainCommentBody {
  text: Text
}

type MarkdownCommentBody {
  text: Text
}

union CommentBody = PlainCommentBody | MarkdownCommentBody

type Comment implements Node {
  actor: Actor
  actors: [Actor]
  actorCount: Int
  address: StreetAddress
  allPhones: [Phone]
  author: User
  backgroundImage: Image
  birthdate: Date
  body: Text
  canViewerComment: Boolean
  canViewerLike: Boolean
  commentBody(supported: [String!]!): CommentBody
  comments(first: Int, last: Int, orderby: String): CommentsConnection
  doesViewerLike: Boolean
  emailAddresses: [String]
  feedback: Feedback
  firstName(if: Boolean, unless: Boolean): String
  friends(after: ID, before: ID, first: Int, last: Int, orderby: [String], find: String, isViewerFriend: Boolean, if: Boolean, unless: Boolean, traits: [PersonalityTraits]): FriendsConnection
  hometown: Page
  id: ID!
  lastName: String
  likers(first: Int): LikersOfContentConnection
  likeSentence: Text
  message: Text
  name: String
  profilePicture(size: [Int], preset: PhotoSize): Image
  segments(first: Int): Segments
  screennames: [Screenname]
  subscribeStatus: String
  subscribers(first: Int): SubscribersConnection
  topLevelComments(first: Int): TopLevelCommentsConnection
  tracking: String
  url(relative: Boolean, site: String): String
  websites: [String]
  username: String
  viewerSavedState: String
}

type CommentCreateResponsePayload {
  clientMutationId: String
  comment: Comment
  feedback: Feedback
  feedbackCommentEdge: CommentsEdge
  viewer: Viewer
}

type CommentDeleteResponsePayload {
  clientMutationId: String
  deletedCommentId: ID
  feedback: Feedback
}

type CommentsConnection {
  count: Int
  edges: [CommentsEdge]
  pageInfo: PageInfo
}

type CommentsEdge {
  cursor: String
  node: Comment
  source: Feedback
}

type ConfigsConnection {
  edges: [ConfigsConnectionEdge]
  pageInfo: PageInfo
}

type ConfigsConnectionEdge {
  node: Config
}

type Config {
  name: String
  isEnabled: Boolean
}

type Date {
  day: Int
  month: Int
  year: Int
}

type Feedback implements Node {
  actor: Actor
  actors: [Actor]
  actorCount: Int
  address: StreetAddress
  allPhones: [Phone]
  author: User
  backgroundImage: Image
  birthdate: Date
  body: Text
  canViewerComment: Boolean
  canViewerLike: Boolean
  comments(first: Int, last: Int, orderby: String): CommentsConnection
  doesViewerLike: Boolean
  emailAddresses: [String]
  feedback: Feedback
  firstName(if: Boolean, unless: Boolean): String
  friends(after: ID, before: ID, first: Int, last: Int, orderby: [String], find: String, isViewerFriend: Boolean, if: Boolean, unless: Boolean, traits: [PersonalityTraits]): FriendsConnection
  hometown: Page
  id: ID!
  lastName: String
  likers(first: Int): LikersOfContentConnection
  likeSentence: Text
  message: Text
  name: String
  profilePicture(size: [Int], preset: PhotoSize): Image
  segments(first: Int): Segments
  screennames: [Screenname]
  subscribeStatus: String
  subscribers(first: Int): SubscribersConnection
  topLevelComments(orderBy: [TopLevelCommentsOrdering], first: Int): TopLevelCommentsConnection
  tracking: String
  url(relative: Boolean, site: String): String
  websites: [String]
  username: String
  viewerSavedState: String
}

type FeedbackLikeResponsePayload {
  clientMutationId: String
  clientSubscriptionId: String
  feedback: Feedback
}

interface FeedUnit {
  actor: Actor
  actorCount: Int
  feedback: Feedback
  id: ID!
  message: Text
  tracking: String
}

type FriendsConnection {
  count: Int
  edges: [FriendsEdge]
  pageInfo: PageInfo
}

type FriendsEdge {
  cursor: String
  node: User
  source: User
}

type Image {
  uri: String
  width: Int
  height: Int
}

type LikersOfContentConnection {
  count: Int
  edges: [LikersEdge]
  pageInfo: PageInfo
}

type LikersEdge {
  cursor: String
  node: Actor
}

interface Named {
  name: String
}

type SimpleNamed implements Named {
  name: String
}

type NewsFeedConnection {
  edges: [NewsFeedEdge]
  pageInfo: PageInfo
}

type NewsFeedEdge {
  cursor: String
  node: FeedUnit
  sortKey: String
  showBeeper: Boolean
}

interface Node {
  actor: Actor
  actors: [Actor]
  actorCount: Int
  address: StreetAddress
  allPhones: [Phone]
  author: User
  backgroundImage: Image
  birthdate: Date
  body: Text
  canViewerComment: Boolean
  canViewerLike: Boolean
  comments(first: Int, last: Int, orderby: String): CommentsConnection
  doesViewerLike: Boolean
  emailAddresses: [String]
  feedback: Feedback
  firstName(if: Boolean, unless: Boolean): String
  friends(after: ID, before: ID, first: Int, last: Int, orderby: [String], find: String, isViewerFriend: Boolean, if: Boolean, unless: Boolean, traits: [PersonalityTraits]): FriendsConnection
  hometown: Page
  id: ID!
  lastName: String
  likers(first: Int): LikersOfContentConnection
  likeSentence: Text
  message: Text
  name: String
  profilePicture(size: [Int], preset: PhotoSize): Image
  segments(first: Int): Segments
  screennames: [Screenname]
  subscribeStatus: String
  subscribers(first: Int): SubscribersConnection
  topLevelComments(first: Int): TopLevelCommentsConnection
  tracking: String
  url(relative: Boolean, site: String): String
  websites: [String]
  username: String
  viewerSavedState: String
}

interface Actor {
  address: StreetAddress
  allPhones: [Phone]
  birthdate: Date
  emailAddresses: [String]
  firstName(if: Boolean, unless: Boolean): String
  friends(after: ID, before: ID, first: Int, last: Int, orderby: [String], find: String, isViewerFriend: Boolean, if: Boolean, unless: Boolean, traits: [PersonalityTraits]): FriendsConnection
  hometown: Page
  id: ID!
  lastName: String
  name: String
  nameRenderer(supported: [String!]!): UserNameRenderer
  profilePicture(size: [Int], preset: PhotoSize): Image
  screennames: [Screenname]
  subscribeStatus: String
  subscribers(first: Int): SubscribersConnection
  url(relative: Boolean, site: String): String
  websites: [String]
  username: String
}

type NodeSavedStateResponsePayload {
  node: Node
}

type Page implements Node & Actor {
  actor: Actor
  actors: [Actor]
  actorCount: Int
  address: StreetAddress
  allPhones: [Phone]
  author: User
  backgroundImage: Image
  birthdate: Date
  body: Text
  canViewerComment: Boolean
  canViewerLike: Boolean
  comments(first: Int, last: Int, orderby: String): CommentsConnection
  doesViewerLike: Boolean
  emailAddresses: [String]
  feedback: Feedback
  firstName(if: Boolean, unless: Boolean): String
  friends(after: ID, before: ID, first: Int, last: Int, orderby: [String], find: String, isViewerFriend: Boolean, if: Boolean, unless: Boolean, traits: [PersonalityTraits]): FriendsConnection
  hometown: Page
  id: ID!
  lastName: String
  likers(first: Int): LikersOfContentConnection
  likeSentence: Text
  message: Text
  name: String
  nameRenderer(supported: [String!]!): UserNameRenderer
  profilePicture(size: [Int], preset: PhotoSize): Image
  segments(first: Int): Segments
  screennames: [Screenname]
  subscribeStatus: String
  subscribers(first: Int): SubscribersConnection
  topLevelComments(first: Int): TopLevelCommentsConnection
  tracking: String
  url(relative: Boolean, site: String): String
  websites: [String]
  username: String
  viewerSavedState: String
}

type PageInfo {
  hasPreviousPage: Boolean
  hasNextPage: Boolean
  endCursor: String
  startCursor: String
}

type PendingPostsConnection {
  count: Int
  edges: [PendingPostsConnectionEdge]
  pageInfo: PageInfo
}

type PendingPostsConnectionEdge {
  cursor: String
  node: PendingPost
}

type PendingPost {
  text: String
}

type Phone {
  isVerified: Boolean
  phoneNumber: PhoneNumber
}

type PhoneNumber {
  displayNumber: String
  countryCode: String
}

type Screenname {
  name: String
  service: String
}

type Segments {
  edges: SegmentsEdge
}

type SegmentsEdge {
  node: String
}

type NonNodeStory implements FeedUnit {
  actor: Actor
  actorCount: Int
  feedback: Feedback
  id: ID!
  message: Text
  tracking: String
}

type PhotoStory implements FeedUnit & Node {
  # PhotoStory
  photo: Image

  # FeedUnit
  canViewerDelete: Boolean
  seenState: String

  # Node
  actor: Actor
  actors: [Actor]
  actorCount: Int
  address: StreetAddress
  allPhones: [Phone]
  author: User
  backgroundImage: Image
  birthdate: Date
  body: Text
  canViewerComment: Boolean
  canViewerLike: Boolean
  comments(first: Int, last: Int, orderby: String): CommentsConnection
  doesViewerLike: Boolean
  emailAddresses: [String]
  feedback: Feedback
  firstName(if: Boolean, unless: Boolean): String
  friends(after: ID, before: ID, first: Int, last: Int, orderby: [String], find: String, isViewerFriend: Boolean, if: Boolean, unless: Boolean, traits: [PersonalityTraits]): FriendsConnection
  hometown: Page
  id: ID!
  lastName: String
  likers(first: Int): LikersOfContentConnection
  likeSentence: Text
  message: Text
  name: String
  profilePicture(size: [Int], preset: PhotoSize): Image
  segments(first: Int): Segments
  screennames: [Screenname]
  subscribeStatus: String
  subscribers(first: Int): SubscribersConnection
  topLevelComments(first: Int): TopLevelCommentsConnection
  tracking: String
  url(relative: Boolean, site: String): String
  websites: [String]
  username: String
  viewerSavedState: String
}

type Story implements FeedUnit & Node {
  attachments: [StoryAttachment]

  # FeedUnit
  canViewerDelete: Boolean
  seenState: String

  # Node
  actor: Actor
  actors: [Actor]
  actorCount: Int
  address: StreetAddress
  allPhones: [Phone]
  author: User
  backgroundImage: Image
  birthdate: Date
  body: Text
  canViewerComment: Boolean
  canViewerLike: Boolean
  comments(first: Int, last: Int, orderby: String): CommentsConnection
  doesViewerLike: Boolean
  emailAddresses: [String]
  feedback: Feedback
  firstName(if: Boolean, unless: Boolean): String
  friends(after: ID, before: ID, first: Int, last: Int, orderby: [String], find: String, isViewerFriend: Boolean, if: Boolean, unless: Boolean, traits: [PersonalityTraits]): FriendsConnection
  hometown: Page
  id: ID!
  lastName: String
  likers(first: Int): LikersOfContentConnection
  likeSentence: Text
  message: Text
  name: String
  profilePicture(size: [Int], preset: PhotoSize): Image
  segments(first: Int): Segments
  screennames: [Screenname]
  subscribeStatus: String
  subscribers(first: Int): SubscribersConnection
  topLevelComments(first: Int): TopLevelCommentsConnection
  tracking: String
  url(relative: Boolean, site: String): String
  websites: [String]
  username: String
  viewerSavedState: String
}

type StoryAttachment {
  cache_id: ID!
  target: Story
  styleList: [String]
}

type StreetAddress {
  city: String
  country: String
  postal_code: String
  street: String
}


type SubscribersConnection {
  count: Int
  edges: [FriendsEdge]
  pageInfo: PageInfo
}

type SubscribersEdge {
  cursor: String
  node: User
  source: User
}

type Text {
  text: String
  ranges: [String]
}

type TimezoneInfo {
  timezone: String
}

type TopLevelCommentsConnection {
  count: Int
  edges: [CommentsEdge]
  pageInfo: PageInfo
  totalCount: Int
}

input UnfriendInput {
  clientMutationId: String
  friendId: ID
}

type UnfriendResponsePayload {
  actor: Actor
  clientMutationId: String
  formerFriend: User
}

scalar JSDependency

interface HasJsField {
  js(module: String): JSDependency
}

type PlainUserNameRenderer implements HasJsField {
  plaintext: String
  data: PlainUserNameData
  user: User
  js(module: String): JSDependency
}

type PlainUserNameData {
  id: ID
  text: String
}

type MarkdownUserNameRenderer implements HasJsField {
  markdown: String
  data: MarkdownUserNameData
  user: User
  js(module: String): JSDependency
}

type MarkdownUserNameData {
  id: ID
  markup: String
}

type CustomNameRenderer {
  customField: String
}

union UserNameRenderer = PlainUserNameRenderer | MarkdownUserNameRenderer | CustomNameRenderer

type User implements Named & Node & Actor {
  actor: Actor
  actors: [Actor]
  actorCount: Int
  address: StreetAddress
  allPhones: [Phone]
  author: User
  backgroundImage: Image
  birthdate: Date
  body: Text
  canViewerComment: Boolean
  canViewerLike: Boolean
  checkins(environments: [Environment!]!): CheckinSearchResult
  comments(first: Int, last: Int, orderby: String): CommentsConnection
  doesViewerLike: Boolean
  emailAddresses: [String]
  feedback: Feedback
  firstName(if: Boolean, unless: Boolean): String
  friends(
    after: ID
    before: ID
    first: Int
    last: Int
    orderby: [String]
    named: String
    scale: Float
    find: String
    isViewerFriend: Boolean
    if: Boolean
    unless: Boolean
    traits: [PersonalityTraits]
  ): FriendsConnection
  hometown: Page
  id: ID!
  lastName: String
  likers(first: Int): LikersOfContentConnection
  likeSentence: Text
  message: Text
  name: String
  nameRenderer(supported: [String!]!): UserNameRenderer
  storySearch(query: StorySearchInput): [Story]
  storyCommentSearch(query: StoryCommentSearchInput): [Comment]
  profilePicture(size: [Int], preset: PhotoSize): Image
  profile_picture(scale: Float): Image
  segments(first: Int): Segments
  screennames: [Screenname]
  subscribeStatus: String
  subscribers(first: Int): SubscribersConnection
  topLevelComments(first: Int): TopLevelCommentsConnection
  tracking: String
  traits: [PersonalityTraits]
  url(relative: Boolean, site: String): String
  websites: [String]
  username: String
  viewerSavedState: String
}

input StorySearchInput {
  text: String
  limit: Int
  offset: Int
  type: StoryType
}

input StoryCommentSearchInput {
  text: String
  limit: Int
  offset: Int
}

type ItemFilterResult {
  date: String
}

input ItemFilterInput {
  date: String
}

type Viewer {
  configs(named: [String]): ConfigsConnection
  actor: Actor
  allTimezones: [TimezoneInfo]
  isFbEmployee: Boolean
  newsFeed(after: ID, first: Int, find: ID): NewsFeedConnection
  notificationStories(after: ID, first: Int): NewsFeedConnection
  pendingPosts(first: Int): PendingPostsConnection
  primaryEmail: String
  timezoneEstimate: TimezoneInfo
  marketplace_explore(
    marketplace_browse_context: MarketplaceBrowseContext,
    with_price_between: [Float],
  ): MarketplaceExploreConnection
}

type MarketplaceExploreConnection {
  count: Int
}

type ViewerNotificationsUpdateAllSeenStateResponsePayload {
  stories: [Story]
}

enum Environment {
  WEB
  MOBILE
}

enum MarketplaceBrowseContext {
  BROWSE_FEED
  CATEGORY_FEED
}

enum PhotoSize {
  SMALL
  LARGE
}

enum PersonalityTraits {
  CHEERFUL
  DERISIVE
  HELPFUL
  SNARKY
}

enum StoryType {
  DIRECTED
  UNDIRECTED
}

enum TopLevelCommentsOrdering {
  chronological
  ranked_threaded
  recent_activity
  toplevel
}

type Settings {
  cache_id: ID
  notificationSounds: Boolean
  notifications(environment: Environment): Boolean
}
`;

describe('github issue #165: Add support for `directives` in SDL', () => {
  it('should populate schema via `addTypeDefs()`', async () => {
    schemaComposer.clear();
    schemaComposer.addTypeDefs(typeDefs);
    expect(Array.from(schemaComposer.types.keys())).toEqual(
      expect.arrayContaining([
        'String',
        'Float',
        'Int',
        'Boolean',
        'ID',
        'MaybeNode',
        'FakeNode',
        'NonNode',
        'NeverNode',
        'Task',
        'WayPoint',
        'Route',
        'RouteStep',
        'ActorSubscribeInput',
        'ActorNameChangeInput',
        'ApplicationRequestDeleteAllInput',
        'CommentCreateInput',
        'CommentfeedbackFeedback',
        'FeedbackcommentComment',
        'CommentCreateSubscriptionInput',
        'CommentDeleteInput',
        'FeedbackLikeInput',
        'NodeSaveStateInput',
        'UpdateAllSeenStateInput',
        'ActorSubscribeResponsePayload',
        'ActorNameChangePayload',
        'ApplicationRequestDeleteAllResponsePayload',
        'CheckinSearchResult',
        'CheckinSearchInput',
        'PlainCommentBody',
        'MarkdownCommentBody',
        'CommentBody',
        'Comment',
        'CommentCreateResponsePayload',
        'CommentDeleteResponsePayload',
        'CommentsConnection',
        'CommentsEdge',
        'ConfigsConnection',
        'ConfigsConnectionEdge',
        'Config',
        'Feedback',
        'FeedbackLikeResponsePayload',
        'FeedUnit',
        'FriendsConnection',
        'FriendsEdge',
        'Image',
        'LikersOfContentConnection',
        'LikersEdge',
        'Named',
        'SimpleNamed',
        'NewsFeedConnection',
        'NewsFeedEdge',
        'Node',
        'Actor',
        'NodeSavedStateResponsePayload',
        'Page',
        'PageInfo',
        'PendingPostsConnection',
        'PendingPostsConnectionEdge',
        'PendingPost',
        'Phone',
        'PhoneNumber',
        'Screenname',
        'Segments',
        'SegmentsEdge',
        'NonNodeStory',
        'PhotoStory',
        'Story',
        'StoryAttachment',
        'StreetAddress',
        'SubscribersConnection',
        'SubscribersEdge',
        'Text',
        'TimezoneInfo',
        'TopLevelCommentsConnection',
        'UnfriendInput',
        'UnfriendResponsePayload',
        'JSDependency',
        'HasJsField',
        'PlainUserNameRenderer',
        'PlainUserNameData',
        'MarkdownUserNameRenderer',
        'MarkdownUserNameData',
        'CustomNameRenderer',
        'UserNameRenderer',
        'User',
        'StorySearchInput',
        'StoryCommentSearchInput',
        'ItemFilterResult',
        'ItemFilterInput',
        'Viewer',
        'MarketplaceExploreConnection',
        'ViewerNotificationsUpdateAllSeenStateResponsePayload',
        'Environment',
        'MarketplaceBrowseContext',
        'PhotoSize',
        'PersonalityTraits',
        'StoryType',
        'TopLevelCommentsOrdering',
        'Settings',
        'Query',
        'Mutation',
        'Subscription',
      ])
    );
    const SettingTC = schemaComposer.getOTC('Settings');
    expect(SettingTC.getFieldNames()).toEqual(['cache_id', 'notificationSounds', 'notifications']);
  });
});
